package game

import (
	"context"
	"database/sql"
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"navi-mumbai/common/gensql"
)

var _ GameModel = (*customGameModel)(nil)

type (
	// GameModel is an interface to be customized, add more methods here,
	// and implement the added methods in customGameModel.
	GameModel interface {
		gameModel
		Find(ctx context.Context, providerId int64, state int64, pageNo, pageSize int64) ([]*Game, error)
		FindGameList(ctx context.Context) ([]*Game, error)
		Count(ctx context.Context, providerId int64, state int64) (int64, error)
		UpdateGame(ctx context.Context, update *UpdateGame) error
		Trans(ctx context.Context, fn func(context context.Context, tx sqlx.Session) error) error
	}

	customGameModel struct {
		*defaultGameModel
		genSql *gensql.GenSql
		logx.Logger
	}
)

// NewGameModel returns a model for the database table.
func NewGameModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) GameModel {
	return &customGameModel{
		defaultGameModel: newGameModel(conn, c, opts...),
		genSql:           gensql.NewGenSql(),
	}
}

func (m *customGameModel) Trans(ctx context.Context, fn func(ctx context.Context, tx sqlx.Session) error) error {
	return m.TransactCtx(ctx, func(ctx context.Context, tx sqlx.Session) error {
		return fn(ctx, tx)
	})
}

func (m *customGameModel) FindGameList(ctx context.Context) ([]*Game, error) {
	q := fmt.Sprintf("select %s from %s ", gameRows, m.table)
	m.genSql.InitSql(q)
	query, values, err := m.genSql.OrderBy("create_time ASC").ToSql()
	if err != nil {
		return nil, err
	}
	resp := make([]*Game, 0)
	err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
	switch err {
	case nil:
		return resp, nil
	default:
		return nil, err
	}
}

func (m *customGameModel) Find(ctx context.Context, providerId int64, state int64, pageNo, pageSize int64) ([]*Game, error) {
	// 分页
	if pageNo < 1 {
		pageNo = 1
	}
	if pageSize <= 0 {
		pageSize = 10
	}
	q := fmt.Sprintf("select %s from %s ", gameRows, m.table)
	m.genSql.InitSql(q)
	if providerId != 0 {
		m.genSql = m.genSql.Where("provider_id = ?", providerId)
	}
	if state != 0 {
		m.genSql = m.genSql.Where("state = ?", state)
	}
	query, values, err := m.genSql.OrderBy("create_time ASC").Limit(uint64(pageSize)).Offset(uint64((pageNo - 1) * pageSize)).ToSql()
	if err != nil {
		return nil, err
	}

	resp := make([]*Game, 0)
	err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
	switch err {
	case nil:
		return resp, nil
	default:
		return nil, err
	}
}

func (m *customGameModel) Count(ctx context.Context, providerId int64, state int64) (int64, error) {
	q := fmt.Sprintf("select count(game_id) from %s ", m.table)
	m.genSql.InitSql(q)
	if providerId != 0 {
		m.genSql = m.genSql.Where("provider_id = ?", providerId)
	}

	if state != 0 {
		m.genSql = m.genSql.Where("state = ?", state)
	}

	query, values, err := m.genSql.ToSql()
	if err != nil {
		return 0, err
	}

	var resp int64
	err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
	switch err {
	case nil:
		return resp, nil
	default:
		return 0, err
	}
}

type UpdateGame struct {
	ProviderId int64  // 游戏供应商id
	GGameId    string // G端游戏id
	GameId     int64
	GameName   string // 游戏名称
	GameLogo   string // 游戏logo文件名
	GameType   string // 游戏类型
	GameUrl    string // 游戏链接
	InstantId  string // 游戏实例id
	State      int64  // 游戏状态
}

func (m *customGameModel) UpdateGame(ctx context.Context, update *UpdateGame) error {
	q := fmt.Sprintf("update %s ", m.table)
	m.genSql.InitSql(q)
	if update.GameName != "" {
		m.genSql = m.genSql.Set("game_name", update.GameName)
	}
	if update.GameLogo != "" {
		m.genSql = m.genSql.Set("game_logo", update.GameLogo)
	}
	if update.GameType != "" {
		m.genSql = m.genSql.Set("game_type", update.GameType)
	}
	if update.GameUrl != "" {
		m.genSql = m.genSql.Set("game_url", update.GameUrl)
	}
	if update.InstantId != "" {
		m.genSql = m.genSql.Set("instant_id", update.InstantId)
	}
	if update.State != 0 {
		m.genSql = m.genSql.Set("state", update.State)
	}
	q, v, err := m.genSql.Where("game_id = ?", update.GameId).ToSql()
	if err != nil {
		return err
	}

	if m.Logger == nil {
		m.Logger = logx.WithContext(ctx)
	}
	m.Logger.Infof("UpdateGame sql == %s ", q)

	mumbaiGameGameGameIdKey := fmt.Sprintf("%s%v", cacheMumbaiGameGameGameIdPrefix, update.GameId)
	mumbaiGameGameProviderIdProviderGameIdKey := fmt.Sprintf("%s%v:%v", cacheMumbaiGameGameProviderIdProviderGameIdPrefix, update.ProviderId, update.GGameId)
	_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
		return conn.ExecCtx(ctx, q, v...)
	}, mumbaiGameGameGameIdKey, mumbaiGameGameProviderIdProviderGameIdKey)
	return err
}
